Skip to content

async: a vectored write the caller can await - #24

Merged
EdmondDantes merged 2 commits into
true-asyncfrom
24-awaitable-vectored-write
Aug 20, 2026
Merged

async: a vectored write the caller can await#24
EdmondDantes merged 2 commits into
true-asyncfrom
24-awaitable-vectored-write

Conversation

@EdmondDantes

Copy link
Copy Markdown

Needed by true-async/php-async and true-async/server: the HTTP/1 server frees a write buffer that libuv still points at, because the only write that reports its status is also the only one that leaves the buffer with the caller.

Both vectored modes are fire-and-forget — io_pipe_writev_cb sends no NOTIFY and its release callback takes no status — so a caller that needs the outcome must use the single-buffer write, keep the buffer, and free it when its own wait ends. Once the waiting coroutine is cancelled that moment arrives before the write completes, and the freed bytes stay in libuv's queue.

ZEND_ASYNC_IO_WRITEV_AWAIT marks a vectored write as awaited. Buffer ownership is unchanged — it stays whatever the mode says — and only the completion differs: the request stays alive and io->event is notified with the request as the result and no exception, so a caller matching by request pointer wakes while sibling awaiters on the same handle do not.

Header only. The flags word already existed, so nothing changes signature and ZEND_ASYNC_IO_WRITEV_ZSTR / _IOV keep their values; _MODE_MASK names the bit they occupy. The reactor side is true-async/php-async, the consumer is true-async/server.

The vectored write is fire-and-forget in both of its modes: the completion
sends no notification and the release callback carries no status. A caller
that needs the outcome therefore has to use the single-buffer write, which
does not take the buffer over — so it must free it itself, and the only
moment it can is when its own wait ends. Those are different moments once
the waiting coroutine is cancelled: the wait is over and the write is not.

ZEND_ASYNC_IO_WRITEV_AWAIT says the caller waits. Ownership stays the mode's;
the completion keeps the request alive and notifies io->event with the request
as the result and no exception, so a caller matching by request pointer wakes
and no sibling awaiter on the same handle does.

Header only: the flag word already existed, so no signature changes and the
existing values keep their meaning.
@EdmondDantes
EdmondDantes merged commit 0780317 into true-async Aug 20, 2026
9 of 17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant